package com.sztx.pay.center.core.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
//import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
//import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.StringUtils;

import com.alibaba.dubbo.common.logger.LogMsgNoConverter;
import com.alibaba.fastjson.JSONObject;
import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.Constance.CardActType;
import com.sztx.pay.center.common.util.Constance.CardType;
import com.sztx.pay.center.common.util.Constance.DistributeType;
import com.sztx.pay.center.common.util.Constance.IdCardType;
import com.sztx.pay.center.common.util.Constance.PayFlowState;
import com.sztx.pay.center.common.util.Constance.PayFlowType;
import com.sztx.pay.center.common.util.Constance.RefundOrderType;
import com.sztx.pay.center.common.util.Constance.TradeOrderType;
import com.sztx.pay.center.common.util.Constance.UserActType;
import com.sztx.pay.center.common.util.StringUtil;
import com.sztx.pay.center.common.util.ValidateUtil;
import com.sztx.pay.center.common.yhbf.YHBFSensitiveEnc;
import com.sztx.pay.center.core.service.ActService;
import com.sztx.pay.center.core.service.BillnoService;
import com.sztx.pay.center.core.service.PayCoreCallBack;
import com.sztx.pay.center.core.service.PayCoreService;
import com.sztx.pay.center.core.service.UserInfoService;
import com.sztx.pay.center.core.service.bean.BatchActTransferReq;
import com.sztx.pay.center.core.service.bean.BatchPayCoreTransferReq;
import com.sztx.pay.center.core.service.bean.BatchTransferDetail;
import com.sztx.pay.center.core.service.bean.PayCoreAccountInfo;
import com.sztx.pay.center.core.service.bean.PayCoreBalancePay;
import com.sztx.pay.center.core.service.bean.PayCoreDistribute;
import com.sztx.pay.center.core.service.bean.PayCoreRefund;
import com.sztx.pay.center.core.service.bean.PayCoreResult;
import com.sztx.pay.center.core.service.bean.PayCoreTradeInfo;
import com.sztx.pay.center.core.service.bean.PayCoreTransfer;
import com.sztx.pay.center.core.service.bean.PayCoreTransferReq;
import com.sztx.pay.center.core.service.bean.PayCoreTransferResult;
import com.sztx.pay.center.core.service.bean.TradeInfo;
import com.sztx.pay.center.dataaccess.dao.mysql.PayFlowMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.redis.LockRedisDAO;
import com.sztx.pay.center.dataaccess.domain.PayFlowDO;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.core.context.SpringContextHolder;
import com.sztx.se.core.service.impl.BaseServiceImpl;
import com.sztx.se.rpc.dubbo.client.DubboClientFactory;
import com.sztx.trade.payment.gateway.common.constant.BankCardCustomType;
import com.sztx.trade.payment.gateway.common.distribute.constant.DistributeBankId;
import com.sztx.trade.payment.gateway.common.distribute.constant.DistributeStatus;
import com.sztx.trade.payment.gateway.common.refund.constant.RefundStatus;
import com.sztx.trade.payment.gateway.common.trade.constant.TradeStatus;
import com.sztx.trade.payment.gateway.rpc.api.service.distribute.DistributeRpcService;
import com.sztx.trade.payment.gateway.rpc.api.service.distribute.ReqDistribute;
import com.sztx.trade.payment.gateway.rpc.api.service.distribute.RespDistribute;
import com.sztx.trade.payment.gateway.rpc.api.service.distribute.account.Account;
import com.sztx.trade.payment.gateway.rpc.api.service.distribute.account.AlipayAccount;
import com.sztx.trade.payment.gateway.rpc.api.service.refund.RefundRpcService;
import com.sztx.trade.payment.gateway.rpc.api.service.refund.ReqRefund;
import com.sztx.trade.payment.gateway.rpc.api.service.refund.RespRefund;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.ReqResendTradeVC;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.ReqTrade;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.ReqTrade.GoodInfo;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.ReqTrade.PayAccountInfo;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.ReqVerifyTrade;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.RespResendTradeVC;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.RespTrade;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.RespVerifyTrade;
import com.sztx.trade.payment.gateway.rpc.api.service.trade.TradeRpcService;
import com.sztx.trade.payment.gateway.rpc.api.service.transfer.ReqTransfer;
import com.sztx.trade.payment.gateway.rpc.api.service.transfer.RespTransfer;
import com.sztx.trade.payment.gateway.rpc.api.service.transfer.TransferRpcService;

@Service
public class PayCoreServiceImpl extends BaseServiceImpl implements PayCoreService{
	@Autowired
	private PayFlowMysqlDAO payFlowMysqlDAO;

	@Autowired
	private BillnoService billnoService;
	
	@Autowired(required=false)
	private DubboClientFactory dubboConsumerFactory;
	
	@Autowired
	private LockRedisDAO lockRedisDAO;

	@Autowired
	private ActService  actService;
	
	@Autowired
	private UserInfoService userInfoService;
	
	@Autowired
	@Qualifier("transactionManager")
	private DataSourceTransactionManager txManager;
	
	@Autowired  
	private TaskExecutor taskExecutor;// 线程池  
	
	/**
	 * @param payerAccount
	 * @param tradeInfo
	 * @param serviceName
	 * @param originOrderNo
	 * @return
	 */
	@Override
	public PayCoreResult pay(PayCoreAccountInfo payerAccount, TradeInfo tradeInfo, String serviceName) {		
		
		ValidateUtil.notNull(payerAccount, "payerAccount不能为空");
		ValidateUtil.notNull(tradeInfo, "tradeInfo不能为空");
			
		String userId = payerAccount.getPayerUserId();
		Integer userType = payerAccount.getPayerUserType();
		String actNo = payerAccount.getPayerActNo();
		UserActType actType = payerAccount.getPayerActType();		
		String bankId = tradeInfo.getBankId();
		String tradeOrderId = tradeInfo.getTradeOrderId();		
		TradeOrderType tradeOrderType = tradeInfo.getOrderType();
		long amount = tradeInfo.getAmount();
		String goodsDetail = tradeInfo.getGoodsDetail();
		String goodsName = tradeInfo.getGoodsName();
		String notifyUrl = tradeInfo.getNotifyUrl();
		String returnUrl = tradeInfo.getReturnUrl();
		String originOrderNo = tradeInfo.getOriginOrderNo();
		long feeAmount = tradeInfo.getFeeAmount();//手续费
		String businessType = tradeInfo.getBusinessType();
		String authCode = tradeInfo.getAuthCode();
		
		String remark = tradeInfo.getRemark();
		String gateWayChannelId = tradeInfo.getGateWayChannelId();
		String routeNo = tradeInfo.getRouteNo();
		
	
		ValidateUtil.isNotBlank(userId, "userId不能为空");
		ValidateUtil.notNull(userType, "userType不能为空");
		ValidateUtil.isNotBlank(actNo, "actNo不能为空");
		ValidateUtil.notNull(actType, "actType不能为空");		
		ValidateUtil.isNotBlank(bankId, "bankId不能为空");
		if (feeAmount < 0) {
			throw new BusinessException("feeAmount不能小于0");
		}
		
		ValidateUtil.isNotBlank(tradeOrderId, "tradeOrderId不能为空");
		ValidateUtil.notNull(tradeOrderType, "tradeOrderType不能为空");
		ValidateUtil.gt(amount, 0l, "交易金额必须大于0");
		
		String cardNo = payerAccount.getBankAct();  //银行卡号
		String identityNo = payerAccount.getIdentityNo();
		String mobile = payerAccount.getMobile();
		String realName = payerAccount.getRealName();
		CardActType cardActType = payerAccount.getCardActType();
		CardType cardType = payerAccount.getCardType();
		String expire = payerAccount.getBankActExpire();
		String cvv = payerAccount.getBankActCvv();
		
		
		PayAccountInfo payAccountInfo = new PayAccountInfo();
		payAccountInfo.setBankId(bankId);
		
		
		PayFlowDO payFlow = new PayFlowDO();
		payFlow.setTradeOrderNo(tradeOrderId);
		payFlow.setTradeOrderType(tradeOrderType.getCode());
		payFlow.setPayerUserId(userId);
		payFlow.setPayerUserType(userType);
		payFlow.setFeeAmount(feeAmount);
		payFlow.setBusinessType(businessType);
		
		if (bankId.startsWith("0")) { //余额支付
			throw new BusinessException("bankId="+bankId+"传为有误");
		}else if (bankId.startsWith("1")) {//网银支付
						
		}else if (bankId.startsWith("2")) {//快捷支付			
			ValidateUtil.isNotBlank(cardNo, "快捷支付,cardNo不能为空");
			ValidateUtil.isNotBlank(identityNo, "快捷支付,identityNo不能为空");
			ValidateUtil.isNotBlank(mobile, "快捷支付,mobile不能为空");
			ValidateUtil.isNotBlank(realName, "快捷支付,realName不能为空");
			
			ValidateUtil.notNull(cardActType, "快捷支付,cardActType不能为空");
			ValidateUtil.notNull(cardType, "快捷支付,cardType不能为空");
			
			if (cardActType == CardActType.CARD_ACT_PUBLIC) {
				throw new BusinessException("暂不支持对公银行卡支付");
			}
			
			if (cardType == CardType.CARD_CREDIT) {
				ValidateUtil.notNull(expire, "信用卡支付,expire不能为空");
				ValidateUtil.notNull(cvv, "信用卡支付,cvv不能为空");
				
				payFlow.setPayerBankActCvv(cvv);
				payFlow.setPayerBankActExpire(expire);
				
				payAccountInfo.setCvv(cvv);
				payAccountInfo.setExpireDate(expire);				
			}
			
			mobile = YHBFSensitiveEnc.sensitiveEnc(payerAccount.getMobile(), "mob");
			identityNo = YHBFSensitiveEnc.sensitiveEnc(payerAccount.getIdentityNo(), "identityno");
			cardNo = YHBFSensitiveEnc.sensitiveEnc(payerAccount.getBankAct(), "cardno");
			
			
			payFlow.setPayerBankAct(cardNo);			
			payFlow.setPayerBankActName(realName);
			payFlow.setPayerBankName(payerAccount.getBankName());
			payFlow.setPayerCardActType(cardActType.getValue());
			payFlow.setPayerCardType(cardType.getValue());	
			payFlow.setPayerIdentityNo(identityNo);	
			payFlow.setPayerIdentityType(IdCardType.IC_IDCARD.getCode());
			payFlow.setPayerMobile(mobile);	
			
			payAccountInfo.setBankCardNo(cardNo);
			payAccountInfo.setPhone(payerAccount.getMobile());
			payAccountInfo.setCardType(cardType.getValue());
			payAccountInfo.setIdType(IdCardType.IC_IDCARD.getCode());
			payAccountInfo.setIdNo(identityNo);
			payAccountInfo.setRealName(realName);
			payAccountInfo.setPhone(mobile);
			
		}else if (bankId.startsWith("3")) {//第三方支付
			payAccountInfo.setOpenId(payerAccount.getOpenId());        //微信公众号支付需要的参数
		}else {
			throw new BusinessException("bankId="+bankId+"传为有误");
		}
		
		payAccountInfo.setPassCipherPay(tradeInfo.isPassCipherPay());
		
		//微信公从号支付
		payAccountInfo.setOpenId(payerAccount.getOpenId());
		
		//反扫支付（支付宝、微信）
		if (StringUtil.isNotBlank(authCode)) {			
			payAccountInfo.setAuthCode(authCode);
		}
		
		payFlow.setPayeeUserId(userId);
		payFlow.setPayeeUserType(userType);
		payFlow.setPayeeActType(actType.getCode());
		payFlow.setPayeeActNo(actNo);

		payFlow.setAmount(tradeInfo.getAmount());
		//1 支付 2 转账  3 提现  4退款 5代发
		payFlow.setPayType(Constance.PayFlowType.PAY.getCode());
		payFlow.setRemark(tradeInfo.getRemark());
		payFlow.setCallBackServiceName(serviceName);
		payFlow.setOriginOrderNo(originOrderNo);
		payFlow.setRemark(remark);
		payFlow.setInnerRemark(Constance.PayFlowType.PAY.getDesc());

		String payFlowNo = recordOrder(payFlow);
		ReqTrade tradeRequest = new ReqTrade();
		
		GoodInfo goodInfo = new GoodInfo();
		goodInfo.setGoodName(goodsName);
		goodInfo.setGoodDesc(goodsDetail);

		tradeRequest.setOrderId(payFlowNo);
		tradeRequest.setUserId(userId);
		tradeRequest.setAccountId("");
		tradeRequest.setAmount((int) amount);
		tradeRequest.setAttach(remark);
		tradeRequest.setGoodInfo(goodInfo);
		tradeRequest.setCallbackUrl(notifyUrl);
		tradeRequest.setRedirectUrl(returnUrl);
//		tradeRequest.setChannelId(channelId);
		
		
		tradeRequest.setPayAccountInfo(payAccountInfo);
		tradeRequest.setOriginOrderNo(originOrderNo);
		tradeRequest.setChannelId(gateWayChannelId);
		
		tradeRequest.setRouteNo(routeNo);
		if (StringUtil.isNotBlank(originOrderNo) && originOrderNo.startsWith("BC")) {
			tradeRequest.setRouteNo("000003");
		}
		
		
		
		LOG.info("routeNo:"+routeNo);
		LOG.info("GateWay Trade Request:"+JSONObject.toJSONString(tradeRequest));
		
		TradeRpcService tradeRpcService = dubboConsumerFactory.getDubboClient("gateWayTradeRpcService");
		RespTrade tradeResponse = tradeRpcService.trade(tradeRequest);

		return handPayResult(tradeResponse, false);
	}
	
	
	@Override
	public void resendQuickVC(String orderId) {
		
		PayFlowDO payFlow = payFlowMysqlDAO.findByTradeOrder(orderId);
		
		if (payFlow == null) {
			LOG.warn("重新发送快捷支付绑卡短信验证码，未找到该订单"+orderId);
			
			throw new BusinessException("重新发送快捷支付绑卡短信验证码，未找到该订单"+orderId);
		}
		
		int oldStatus = payFlow.getPayStatus();
		if (!StringUtils.isEmpty(payFlow.getPayerBankAct()) && Constance.PayFlowType.PAY.getCode() == payFlow.getPayType() && Constance.PayFlowState.WAITING_PAY.getCode() != oldStatus &&  Constance.PayFlowState.PAYING.getCode() != oldStatus) {						
			LOG.warn("重新发送快捷支付绑卡短信验证码，订单状态为"+PayFlowState.valueOf(oldStatus).getDesc()+"不能继续处理");
			
			throw new BusinessException("重新发送快捷支付绑卡短信验证码，订单状态为"+PayFlowState.valueOf(oldStatus).getDesc()+"不能继续处理");
		}	
		
		TradeRpcService tradeRpcService = dubboConsumerFactory.getDubboClient("gateWayTradeRpcService");
		ReqResendTradeVC request = new ReqResendTradeVC();
		request.setOrderId(payFlow.getPayFlowNo());
		
		RespResendTradeVC resp = tradeRpcService.resendTradeVC(request);
		if (resp == null) {
			LOG.error("调用网关重新发送快捷支付绑卡短信验证码无响应");
			throw new BusinessException("调用重新发送快捷支付绑卡短信验证码无响应");
		}
		
		String resultCode = resp.getResultCode();
		String resultMsg = resp.getResultMsg();
		
		if (!RespResendTradeVC.RC_OK.equals(resultCode)) {
			LOG.error("调用网关支付重新发送快捷支付绑卡短信验证码处理失败,resultMsg:" + resultMsg);
			throw new BusinessException(resultMsg);
		}
		
	}


	@Override
	public PayCoreResult verifyQuickPayTrade(String orderId, String verifyCode) {
		
		PayFlowDO payFlow = payFlowMysqlDAO.findByTradeOrder(orderId);
		if (payFlow == null) {
			
			LOG.warn("验证快捷支付短信验证码，未找到该订单"+orderId);
			return null;			
		}
		
		int oldStatus = payFlow.getPayStatus();
		if (Constance.PayFlowState.WAITING_PAY.getCode() != oldStatus &&  Constance.PayFlowState.PAYING.getCode() != oldStatus) {						
			LOG.warn("验证快捷支付短信验证码，订单状态为"+PayFlowState.valueOf(oldStatus).getDesc()+"不能继续处理");
			
			//订单状态为成功、失败、异常不做处理
			PayCoreResult result = new PayCoreResult();
			
			result.setPayFlowNo(payFlow.getPayFlowNo());
			result.setReferOrderId(payFlow.getTradeOrderNo());
			result.setTradeDesc(payFlow.getRemark());
			result.setTradeSataus(payFlow.getPayStatus());
//			result.setChannelBankId(payFlow.get);
			result.setChannelId(payFlow.getPayChannelId());
			
			return result;	
		}	
		
		TradeRpcService tradeRpcService = dubboConsumerFactory.getDubboClient("gateWayTradeRpcService");
		ReqVerifyTrade tradeRequest = new ReqVerifyTrade();
		tradeRequest.setOrderId(payFlow.getPayFlowNo());
		tradeRequest.setVerifyCode(verifyCode);
		
		RespVerifyTrade resp = tradeRpcService.verifyTrade(tradeRequest);
		if (resp == null) {
			LOG.error("调用网关验证快捷支付无响应");
			return null;
		}
		
		String payFlowNo = resp.getOrderId();
		String resultCode = resp.getResultCode();
		String resultMsg = resp.getResultMsg();
		String tradeOrderId = resp.getTradeOrderId();
		Integer tradeStatus = resp.getTradeStatus();
		String tradeStatusDesc = resp.getTradeStatusDesc();
		String channelBankId = resp.getChannelBankId();
		String channelId = resp.getChannelId();
		
		
		RespTrade tradeResponse = new RespTrade();
		tradeResponse.setChannelBankId(channelBankId);
		tradeResponse.setChannelId(channelId);
		tradeResponse.setOrderId(payFlowNo);
		tradeResponse.setResultCode(resultCode);
		tradeResponse.setResultMsg(resultMsg);
		tradeResponse.setTradeOrderId(tradeOrderId);
		tradeResponse.setTradeStatus(tradeStatus);
		tradeResponse.setTradeStatusDesc(tradeStatusDesc);
		
				
		if (RespVerifyTrade.RC_VERIFY_CODE_INCORRECT.equals(resultCode)) { //		
			throw new BusinessException("验证码输入错误，请重新输入");			
		}else if (RespVerifyTrade.RC_VERIFY_CODE_EXPIRED.equals(resultCode)) {			
			//RC_VERIFY_CODE_EXPIRED有可能是以下3种情况出现：
			//1.之前没有验证成功过，并且超过了次数限制           交易失败
			//2.之前验证成功过,并再次验证                                    交易成功
			//3.之前没有验证成功过，并且超过了时间限制           交易失败
			
			
			tradeResponse.setResultCode(RespTrade.RC_OK);
			
			if (tradeStatus != null && TradeStatus.TS_SUCCEEDED == tradeStatus.intValue()) {
				tradeResponse.setResultCode("交易成功");
			}		
		}
		
		return handPayResult(tradeResponse, true);
	}

	@Override
	public PayCoreResult handPayResult(RespTrade tradeResponse, boolean callOrder) {		
			if (tradeResponse == null) {
				LOG.error("调用支付网关支付无响应");
				throw new BusinessException("系统繁忙，请稍后再试");
			}
			LOG.info("GateWay Trade Response:"+JSONObject.toJSONString(tradeResponse));
			
//			SqlSessionFactory sqlSessionFactory = SpringContextHolder.applicationContext.getBean("sqlSessionFactory", SqlSessionFactory.class);
//			if (sqlSessionFactory != null && LOG.isDebugEnabled()) {
//				Log.debug("" + sqlSessionFactory.g);
//			}
			
			
			
			String resultCode = tradeResponse.getResultCode();
			String resultMsg = tradeResponse.getResultMsg();
			String channelId = tradeResponse.getChannelId();
			String channelBankId = tradeResponse.getChannelBankId();
			Map<String, String> payParams = tradeResponse.getPayParams();
			String payUrl = tradeResponse.getPayUrl();
			Integer tradeStatus = tradeResponse.getTradeStatus();
			String tradeStatusDesc = tradeResponse.getTradeStatusDesc();
			String gateWayOrderId = tradeResponse.getTradeOrderId();
			String payFlowNo = tradeResponse.getOrderId();
			
			String codeImgUrl = tradeResponse.getCodeImgUrl();
			
			
			if(payUrl != null && payUrl.contains("www.yeepay.com")){
				payUrl = Constance.YB_19FEI_PAYURL;
			}
			
			
			
			//无短信支付
			if(tradeResponse.getRespVerifyTrade() != null){
				RespVerifyTrade respVerifyTrade = tradeResponse.getRespVerifyTrade();
				resultCode = respVerifyTrade.getResultCode();
				resultMsg = respVerifyTrade.getResultMsg();
				channelId = respVerifyTrade.getChannelId();
				channelBankId = respVerifyTrade.getChannelBankId();
				tradeStatus = respVerifyTrade.getTradeStatus();
				tradeStatusDesc = respVerifyTrade.getTradeStatusDesc();
				gateWayOrderId = respVerifyTrade.getTradeOrderId();
				payFlowNo = respVerifyTrade.getOrderId();
			}
			
			
	
			if (!RespTrade.RC_OK.equals(resultCode)) {
				LOG.error("订单调用网关支付处理失败："+JSONObject.toJSONString(tradeResponse));
				throw new BusinessException(resultMsg);
			}	
			
			//根据支付订单号查询订单
			//TODO 此处查询订单需要从主库查询
			PayFlowDO payFlow = null;
			PayCoreResult payCoreResult = null;
			PayCoreTradeInfo tradeInfo = null;

			DefaultTransactionDefinition def = new DefaultTransactionDefinition();
			def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.handPayResult");
			def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);	
			TransactionStatus status = txManager.getTransaction(def);
			try {
				
				payFlow = payFlowMysqlDAO.findByIdLock(payFlowNo);
				if (payFlow == null) {
					LOG.error("支付中心未查询到订单：" + payFlowNo);
					throw new BusinessException("支付中心支付结果处理异常："+ JSONObject.toJSONString(tradeResponse));
				}
				
				String businessType = payFlow.getBusinessType();
				
				payCoreResult = new PayCoreResult();				
				payCoreResult.setPayFlowNo(payFlowNo);
				payCoreResult.setReferOrderId(payFlow.getTradeOrderNo());
				payCoreResult.setTradeDesc(tradeStatusDesc);
					
				int oldStatus = payFlow.getPayStatus();
				LOG.info("oldStatus:" + oldStatus);
				if (PayFlowState.WAITING_PAY.getCode() != oldStatus && PayFlowState.PAYING.getCode() != oldStatus) {
						//订单状态为成功、失败、异常不做处理				
					payCoreResult.setTradeSataus(oldStatus);
					payCoreResult.setChannelId(payFlow.getPayChannelId());
					payCoreResult.setChannelBankId(payFlow.getPayChannelId());
					return payCoreResult;
				}
				
				//只处理订单状态为待支付和支付中的订单
				Date mDate = new Date();
				PayFlowDO updatePayFlow = new PayFlowDO();
				updatePayFlow.setPayFlowNo(payFlowNo);
				updatePayFlow.setGatewayOrderNo(gateWayOrderId);
				updatePayFlow.setPayChannelId(channelId);
				updatePayFlow.setModifyTime(mDate);
					//		updatePayFlow.setRemark(tradeStatusDesc);
				if (TradeStatus.TS_SUCCEEDED == tradeStatus.intValue()) { //支付成功
					updatePayFlow.setPayTime(mDate);
					updatePayFlow.setPayStatus(PayFlowState.SUCCESS.getCode()); //1未支付   2 支付中  3 成功 4 失败 5 异常 	
					updatePayFlow.setPayStatusDesc(PayFlowState.SUCCESS.getDesc());
	//				String remark = StringUtil.isBlank(tradeStatusDesc) ? "支付成功": tradeStatusDesc;
	//				updatePayFlow.setRemark(remark);
		
					//updatePayFlow.setPayType(payType);
					payCoreResult.setTradeSataus(PayFlowState.SUCCESS.getCode());
		
						//TODO 支付订单状态变更通知订单系统	
					tradeInfo = new PayCoreTradeInfo();
					tradeInfo.setAmount(payFlow.getAmount());
					tradeInfo.setPayFlowState(PayFlowState.SUCCESS);
					tradeInfo.setChannelId(channelId);
						//TODO 账户加款
					String srcActNo = Constance.ACT_SZTX; //通行中间账户				
					String desActNo = payFlow.getPayeeActNo();				
					long amount = payFlow.getAmount();				
					String originOrderNo = payFlow.getOriginOrderNo();				
					TradeOrderType tradeType = TradeOrderType.valueOf(payFlow.getTradeOrderType());
					
					String tradeMsg = "支付加款";			
					actService.transferAct(srcActNo, desActNo , amount , originOrderNo , payFlowNo , tradeType , tradeMsg, businessType);				
					long feeAmount = payFlow.getFeeAmount(); //交易手续费
					if (feeAmount > 0) {			
						//收益账户
						actService.transferAct(desActNo, Constance.ACT_PROFIT, feeAmount, originOrderNo, payFlowNo, TradeOrderType.TRADE_FEE, tradeMsg, businessType);
					}
					
					} else if (TradeStatus.TS_FAILED == tradeStatus.intValue()) {//支付失败
						updatePayFlow.setPayStatus(PayFlowState.FAIL.getCode());
						updatePayFlow.setPayStatusDesc(PayFlowState.FAIL.getDesc());
						
						String remark = StringUtil.isBlank(tradeStatusDesc) ? "支付失败" : tradeStatusDesc;
						updatePayFlow.setRemark(remark);
		
						payCoreResult.setTradeSataus(PayFlowState.FAIL.getCode());
						
						//TODO 支付订单状态变更通知订单系统	
						tradeInfo = new PayCoreTradeInfo();
						tradeInfo.setPayFlowState(PayFlowState.FAIL);
						tradeInfo.setAmount(0);
						tradeInfo.setChannelId(channelId);
		
					} else if (TradeStatus.TS_PAYING == tradeStatus.intValue() || TradeStatus.TS_INITIALIZING == tradeStatus.intValue()) {//支付中或初始状态
		
						//1.原订单状态为待支付则更改支付状态				
						updatePayFlow.setPayStatus(PayFlowState.PAYING.getCode());
						//2.原订单状态为支付中则不予处理
						if (oldStatus == PayFlowState.PAYING.getCode()) {
							updatePayFlow = null;
						}
		
						payCoreResult.setTradeSataus(Constance.PayFlowState.PAYING.getCode());
						payCoreResult.setPayUrl(payUrl);
						payCoreResult.setChannelId(channelId);
						payCoreResult.setChannelBankId(channelBankId);
						payCoreResult.setPayParams(payParams);
						payCoreResult.setCodeImgUrl(codeImgUrl);
						
					} else { //导常情况(网关返回结果中不能有未知状态即异常态)  不处理
						payCoreResult.setTradeSataus(oldStatus);
						payCoreResult.setChannelId(payFlow.getPayChannelId());
						payCoreResult.setChannelBankId(payFlow.getPayChannelId());
						return payCoreResult;
					}
				
					if (updatePayFlow != null) {
						payFlowMysqlDAO.update(updatePayFlow);
					}
					
			}catch (Exception ex) {
				txManager.rollback(status);
				LOG.error("处理支付结果出错", ex);
				throw new BusinessException(ex);
			}finally{				
				if (!status.isCompleted()) {
					txManager.commit(status);
				}
			}

			if (callOrder && tradeInfo != null) {	
				tradeInfo.setPayFlowType(PayFlowType.valueOf(payFlow.getPayType()));
				tradeInfo.setPayFlowDesc(tradeStatusDesc);
				callBackOrder(tradeInfo, payFlow, payFlow.getCallBackServiceName());
			}
			
			return payCoreResult;
		}


	@Override
	public PayCoreResult distribute(PayCoreDistribute payCoreDistribute, String serviceName) {
		
		long amount = payCoreDistribute.getAmount();
		String attach = payCoreDistribute.getAttach();
		CardActType cadActType = payCoreDistribute.getCardActType();
		String cardCity = payCoreDistribute.getCardCity();
		String cardProvince = payCoreDistribute.getCardProvince();
		String payeeAccountId = payCoreDistribute.getPayeeAccountId();
		UserActType payeeActType = payCoreDistribute.getPayeeActType();
		String payeeUserId = payCoreDistribute.getPayeeUserId();
		Integer userType = payCoreDistribute.getPayeeUserType();
		String realName = payCoreDistribute.getRealName();
		String referOrderId = payCoreDistribute.getReferOrderId();
		TradeOrderType tradeOrderType = payCoreDistribute.getTradeOrderType();
		
		String payerUserId = payCoreDistribute.getPayerUserId();
		Integer payerUserType = payCoreDistribute.getPayerUserType();
		String payerActNo = payCoreDistribute.getPayerActNo();
		UserActType payerActType = payCoreDistribute.getPayerActType();
		String originOrderNo = payCoreDistribute.getOriginOrderNo();
		
		String businessType = payCoreDistribute.getBusinessType();
		String bankId = payCoreDistribute.getBankId();
		
		long feeAmount = payCoreDistribute.getFeeAmount();
		
		
		DistributeType distributeType = payCoreDistribute.getDistributeType();		
		payeeAccountId = YHBFSensitiveEnc.sensitiveEnc(payeeAccountId,"cardno");
		
		PayFlowDO payFlow = new PayFlowDO();
		payFlow.setPayerUserId(payerUserId);
		payFlow.setPayerUserType(payerUserType);
		payFlow.setPayerActType(payerActType.getCode());
		payFlow.setPayerActNo(payerActNo);		
		payFlow.setPayeeUserId(payeeUserId);
		payFlow.setPayeeUserType(userType);
		payFlow.setTradeOrderNo(referOrderId);
		payFlow.setTradeOrderType(tradeOrderType.getCode());
		payFlow.setAmount(amount);
		payFlow.setPayType(PayFlowType.DISTRIBUTE.getCode());
		payFlow.setInnerRemark(PayFlowType.DISTRIBUTE.getDesc());
		payFlow.setRemark(attach);
		payFlow.setCallBackServiceName(serviceName);
		payFlow.setOriginOrderNo(originOrderNo);
		payFlow.setFeeAmount(feeAmount);
		payFlow.setBusinessType(businessType);
		
		String payFlowNo = recordOrder(payFlow);
		
		ReqDistribute req = new ReqDistribute();		
		Account account = null;
		
		switch (distributeType) {
			case ALIPAY:
				AlipayAccount alipayAccount = new AlipayAccount();
				alipayAccount.setAccount(payCoreDistribute.getPayeeAccountId());
				alipayAccount.setName(realName);
				account = alipayAccount;
				req.setBankId(DistributeBankId.DBI_ALIPAY);
				break;
			case BANK:
				com.sztx.trade.payment.gateway.rpc.api.service.distribute.account.BankAccount bankAccount = new com.sztx.trade.payment.gateway.rpc.api.service.distribute.account.BankAccount();
				bankAccount.setCardNo(payeeAccountId);
				bankAccount.setName(realName);
				req.setBankId(bankId);
				if (cadActType == CardActType.CARD_ACT_PUBLIC) {
					bankAccount.setProvince(cardProvince);
					bankAccount.setCity(cardCity);
					bankAccount.setCustomType(BankCardCustomType.BCCT_TO_ORG);
	
				} else {
					bankAccount.setCustomType(BankCardCustomType.BCCT_TO_PERSON);
				}
				account = bankAccount;
				break;
			default:
				break;
		}
		
		long distributeAmount = amount - feeAmount;
		
		req.setAccount(account);
		req.setAmount((int) distributeAmount);
		req.setAttach(attach);	
		req.setCallbackUrl("");
		req.setOrderId(payFlowNo);	
		req.setOriginOrderNo(originOrderNo);
		//冻结账户余额
		actService.freezeMoney(payerActNo, amount, originOrderNo, payFlowNo, new Date(), tradeOrderType, attach, "admin", businessType);
		
		DistributeRpcService distributeRpcService = dubboConsumerFactory.getDubboClient("distributeRpcService");
		LOG.info("GateWay Distribute Request:"+JSONObject.toJSONString(req));
		RespDistribute resp = distributeRpcService.distribute(req);
		
		return handDistributeResult(resp, false);
	}

	@Override
	public PayCoreResult handDistributeResult(RespDistribute result, boolean callOrder) {
		if (result == null) {
			LOG.error("调用支付网关代发无响应");
			throw new BusinessException("系统繁忙，请稍后再试");
		}

		LOG.info("GateWay Distribute Response:" + JSONObject.toJSONString(result));
		// String bankId = result.getChannelBankId();// 转账只是通付的余额转账
		String channelId = result.getChannelId();
		String payFlowNo = result.getOrderId();
		String resultCode = result.getResultCode();
		String resultMsg = result.getResultMsg();
		String transferOrderId = result.getDistributeOrderId();
		int status = result.getDistributeStatus();
		String statusDesc = result.getDistributeStatusDesc();

		if (!RespDistribute.RC_OK.equals(resultCode)) {
			LOG.error("订单调用网关代发处理失败：" + JSONObject.toJSONString(result));
			throw new BusinessException(resultMsg);
		}

		PayCoreResult payCoreResult  = null;
		
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.handDistributeResult");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		try {

			// 根据支付订单号查询订单
			// TODO 此处查询订单需要从主库查询
			PayFlowDO payFlow = payFlowMysqlDAO.findByIdLock(payFlowNo);
			if (payFlow == null) {
				LOG.error("支付中心未查询到订单：" + payFlowNo);
				throw new BusinessException("支付中心支付结果处理异常："+ JSONObject.toJSONString(result));
			}

			String businessType = payFlow.getBusinessType();

			payCoreResult = new PayCoreResult();
			payCoreResult.setPayFlowNo(payFlowNo);
			payCoreResult.setReferOrderId(payFlow.getTradeOrderNo());
			int oldStatus = payFlow.getPayStatus();
			LOG.info("oldStatus:" + oldStatus + " transferOrderId:" + transferOrderId);

			if (Constance.PayFlowState.WAITING_PAY.getCode() != oldStatus && Constance.PayFlowState.PAYING.getCode() != oldStatus) {
				// 订单状态为成功、失败、异常不做处理
				LOG.info("order no pay" + " transferOrderId:" + transferOrderId);

				payCoreResult.setTradeSataus(payFlow.getPayStatus());
				payCoreResult.setTradeDesc(payFlow.getRemark());
				payCoreResult.setChannelId(payFlow.getPayChannelId());

				return payCoreResult;
			}

			long amount = payFlow.getAmount();
			long feeAmount = payFlow.getFeeAmount();
			String payerActNo = payFlow.getPayerActNo();
			String originOrderNo = payFlow.getOriginOrderNo();
			TradeOrderType tradeType = TradeOrderType.valueOf(payFlow.getTradeOrderType());
			String attach = payFlow.getRemark();

			// 只处理订单状态为待支付和支付中的订单
			Date mDate = new Date();
			PayFlowDO updatePayFlow = new PayFlowDO();
			updatePayFlow.setPayFlowNo(payFlowNo);
			updatePayFlow.setGatewayOrderNo(transferOrderId);
			updatePayFlow.setPayChannelId(channelId);
			updatePayFlow.setModifyTime(mDate);
			updatePayFlow.setRemark(statusDesc);
			PayCoreTradeInfo tradeInfo = null;
			if (DistributeStatus.DS_SUCCEEDED == status) { // 支付成功
				updatePayFlow.setPayTime(mDate);
				updatePayFlow.setPayStatus(Constance.PayFlowState.SUCCESS.getCode()); // 1未支付 2 支付中 3 成功 4 失败 5 异常
				updatePayFlow.setPayStatusDesc(PayFlowState.SUCCESS.getDesc());

				// updatePayFlow.setPayType(payType);
				payCoreResult.setTradeSataus(Constance.PayFlowState.SUCCESS.getCode());

				// TODO 支付订单状态变更通知订单系统
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setAmount(payFlow.getAmount());
				tradeInfo.setPayFlowState(PayFlowState.SUCCESS);
				LOG.info("order pay success" + " transferOrderId:" + transferOrderId);

				// 解冻提现金额
				actService.unfreezeMoney(payerActNo, amount, originOrderNo, payFlowNo, new Date(), tradeType, attach, "admin", businessType);
				
				if (feeAmount > 0) {
					actService.transferAct(payerActNo, Constance.ACT_SZTX, amount - feeAmount, originOrderNo, payFlowNo, tradeType, attach, businessType);
					actService.transferAct(payerActNo, Constance.ACT_PROFIT, feeAmount, originOrderNo, payFlowNo, TradeOrderType.TRADE_FEE, attach, businessType); // 手续费
				} else {
					actService.transferAct(payerActNo, Constance.ACT_SZTX, amount, originOrderNo, payFlowNo, tradeType, attach, businessType);
				}
			} else if (DistributeStatus.DS_FAILED == status) {// 支付失败
				
				updatePayFlow.setPayStatus(Constance.PayFlowState.FAIL.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.FAIL.getDesc());
				payCoreResult.setTradeSataus(Constance.PayFlowState.FAIL.getCode());
				payCoreResult.setTradeDesc(statusDesc);
				
				// TODO 支付订单状态变更通知订单系统
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.FAIL);

				// 解冻提现金额
				actService.unfreezeMoney(payerActNo, amount, originOrderNo, payFlowNo, new Date(), tradeType, "提现失败解冻金额", "admin", businessType);

			} else if (DistributeStatus.DS_PROCESSING == status
					|| DistributeStatus.DS_ACCEPTED == status) {// 支付中

				// 1.原订单状态为待支付则更改支付状态
				updatePayFlow.setPayStatus(Constance.PayFlowState.PAYING.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.PAYING.getDesc());
				// 2.原订单状态为支付中则不予处理
				if (oldStatus == Constance.PayFlowState.PAYING.getCode()) {
					updatePayFlow = null;
				}

				payCoreResult.setTradeSataus(Constance.PayFlowState.PAYING.getCode());
				payCoreResult.setChannelId(channelId);
			} else {
				updatePayFlow.setPayStatus(Constance.PayFlowState.EXCEPTION.getCode());
				payCoreResult.setTradeSataus(Constance.PayFlowState.EXCEPTION.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.EXCEPTION.getDesc());
				// TODO 订单状态异常需要预警进行人工干预
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.EXCEPTION);
			}

			if (callOrder && tradeInfo != null) {
				tradeInfo.setPayFlowType(PayFlowType.valueOf(payFlow.getPayType()));
				tradeInfo.setPayFlowDesc(statusDesc);
				callBackOrder(tradeInfo, payFlow, payFlow.getCallBackServiceName());
			}
			// if (callOrder && tradeInfo != null) {
			// LOG.info("===================================");
			// }
			if (updatePayFlow != null) {
				payFlowMysqlDAO.update(updatePayFlow);
			}
	
		} catch (Exception ex) {
			txManager.rollback(transactionStatus);
			LOG.error("处理代发结果出错", ex);
			throw new BusinessException(ex);
		}finally{
			if (!transactionStatus.isCompleted()) {
				txManager.commit(transactionStatus);
			}			
		}

		return payCoreResult;

	}
	
	
	
	private String recordOrder(PayFlowDO payFlow){		
		
		if (payFlow.getPayFlowNo() == null) {
			String payFlowNo = billnoService.nexPayFlowNo();
			payFlow.setPayFlowNo(payFlowNo);
		}
		
		payFlow.setPayStatus(Constance.PayFlowState.WAITING_PAY.getCode());
		payFlow.setPayStatusDesc(Constance.PayFlowState.WAITING_PAY.getDesc());
		
		//TODO 需要判重
		payFlowMysqlDAO.save(payFlow);
		
		return payFlow.getPayFlowNo();
	}
	
	
	/**
	 * 回调订单系统
	 * 
	 * @author xiaosc
	 * @date 2016年2月19日 下午4:52:52 
	 */
	private void callBackOrder(PayCoreTradeInfo tradeInfo, PayFlowDO payFlow, String serviceName){		
		
		this.taskExecutor.execute(new CallBackThread(tradeInfo, payFlow, serviceName, LogMsgNoConverter.getCurrentMsgno()));
	}


	@Override
	public PayCoreResult refund(PayCoreRefund refund, String serviceName) {		
		
		String attach = refund.getAttach();
		long amount = refund.getAmount();		
		long feeAmount = refund.getFeeAmount();

		String refundOrderId = refund.getRefundOrderId();
		String chargeOrderId = refund.getOriginChargeOrderId();
		String payOrderId = refund.getOriginTradeOrderId();
		String businessType = refund.getBusinessType();
		
		ValidateUtil.isNotBlank(refundOrderId, "refundOrderId不能为空");		
		if (StringUtil.isBlank(chargeOrderId) && StringUtil.isBlank(payOrderId)) {
			throw new BusinessException("退款订单号不能为空");
		}
				
		if (amount <= 0) {
			LOG.warn("退款金额小于等0，amount="+amount);
			throw new BusinessException("退款金额必大于0");
		}
		
		if (feeAmount < 0) {
			LOG.warn("退款手续费小于0，feeAmount="+feeAmount);
			throw new BusinessException("退款手续费必须大于等于0");
		}
		
		PayFlowDO chargeOrder = null;      //充值单
		PayFlowDO tradeOrder = null;    //交易单
		
		if (StringUtil.isNotBlank(chargeOrderId)) {
			chargeOrder = payFlowMysqlDAO.findByTradeOrder(chargeOrderId);
			if (chargeOrder == null) {			
				throw new BusinessException("未找订单"+chargeOrderId+"信息");		
			}	
			
			PayFlowType payType = PayFlowType.valueOf(chargeOrder.getPayType());			
			if (payType != PayFlowType.PAY) {
				throw new BusinessException(chargeOrderId+"不是支付订单,不允许退款操作");
			}
			
			PayFlowState payState = PayFlowState.valueOf(chargeOrder.getPayStatus());
			if (payState != PayFlowState.SUCCESS) {
				throw new BusinessException(chargeOrderId+"未支付成功,不允许退款操作");
			}
		}
		
		if (StringUtil.isNotBlank(payOrderId)) {
			tradeOrder = payFlowMysqlDAO.findByTradeOrder(payOrderId);
			if (tradeOrder == null) {			
				throw new BusinessException("未找订单"+payOrderId+"信息");		
			}
			
			PayFlowType payType = PayFlowType.valueOf(tradeOrder.getPayType());			
			if (payType != PayFlowType.BALANCE_TRADE) {
				throw new BusinessException(payOrderId+"不是支付订单,不允许退款操作");
			}
			
			PayFlowState payState = PayFlowState.valueOf(tradeOrder.getPayStatus());
			if (payState != PayFlowState.SUCCESS) {
				throw new BusinessException(payOrderId+"未支付成功,不允许退款操作");
			}
		}
		
		String payFlowNo = billnoService.nexPayFlowNo();
		PayFlowDO refundFlow = new PayFlowDO();
		refundFlow.setPayFlowNo(payFlowNo);
		refundFlow.setAmount(amount);
		refundFlow.setTradeOrderNo(refundOrderId);		
		refundFlow.setTradeOrderType(TradeOrderType.REFUND_ORDER.getCode());
		refundFlow.setFeeAmount(feeAmount);
		refundFlow.setPayStatus(Constance.PayFlowState.WAITING_PAY.getCode());
		refundFlow.setPayStatusDesc(Constance.PayFlowState.WAITING_PAY.getDesc());
		refundFlow.setRemark(attach);	
		refundFlow.setCallBackServiceName(serviceName);
		refundFlow.setPayType(PayFlowType.REFUND.getCode());
		refundFlow.setBusinessType(businessType);
		ReqRefund request = null;
		RespRefund resp = null;
		
		// 格式  type|charageOrderId|tradeOrderId
		// type 1充值单   2余额支付单   3充值支付单
		
		String innerRemak = ""; 	
		RefundOrderType refundOrderType = null;
		
		if (chargeOrder != null && tradeOrder == null) {  //充值单			
			refundFlow.setPayerUserId(chargeOrder.getPayerUserId());
			refundFlow.setPayerUserType(chargeOrder.getPayerUserType());
			refundFlow.setPayerActNo(chargeOrder.getPayerActNo());
			refundFlow.setPayerActType(chargeOrder.getPayerActType());
			refundFlow.setOriginOrderNo(chargeOrder.getOriginOrderNo());

			request = new ReqRefund();
			request.setAmount((int) amount);
			request.setAttach(attach);
			request.setCallbackUrl("");
			request.setOriginOrderId(chargeOrder.getPayFlowNo());
			request.setOriginOrderNo(chargeOrder.getOriginOrderNo());
			request.setOrderId(payFlowNo);  //支付中心退款订单号
			
			refundOrderType = RefundOrderType.CHARAGE;
			innerRemak = RefundOrderType.CHARAGE.getValue() + "|" + chargeOrder.getPayFlowNo();
			
			actService.freezeMoney(chargeOrder.getPayeeActNo(), amount, chargeOrder.getOriginOrderNo(), payFlowNo, chargeOrder.getPayTime(), TradeOrderType.REFUND_ORDER, "退款冻结", "admin", businessType);
			
		}else if (chargeOrder == null && tradeOrder != null) {//余额支付
			
			refundFlow.setPayerUserId(tradeOrder.getPayeeUserId());
			refundFlow.setPayerUserType(tradeOrder.getPayeeUserType());
			refundFlow.setPayerActNo(tradeOrder.getPayeeActNo());
			refundFlow.setPayerActType(tradeOrder.getPayeeActType());
			refundFlow.setOriginOrderNo(tradeOrder.getOriginOrderNo());
			refundFlow.setPayeeUserId(tradeOrder.getPayerUserId());
			refundFlow.setPayeeUserType(tradeOrder.getPayerUserType());
			refundFlow.setPayeeActNo(tradeOrder.getPayerActNo());
			refundFlow.setPayeeActType(tradeOrder.getPayerActType());
			
			refundOrderType = RefundOrderType.TRADE;
			innerRemak = RefundOrderType.TRADE.getValue() + "|" + tradeOrder.getPayFlowNo();
			
		}else if (chargeOrder != null && tradeOrder != null) {//充值并支付
			String chargeOriginOrder = chargeOrder.getOriginOrderNo();
			String tradeOriginOrderNo = tradeOrder.getOriginOrderNo();
			
			if (!chargeOriginOrder.equals(tradeOriginOrderNo)) {			
				throw new BusinessException("订单"+chargeOriginOrder+"与订单"+tradeOriginOrderNo+"不是同笔交易，不允许退款");
			}
			
			refundFlow.setPayerUserId(tradeOrder.getPayeeUserId());
			refundFlow.setPayerUserType(tradeOrder.getPayeeUserType());
			refundFlow.setPayerActNo(tradeOrder.getPayeeActNo());
			refundFlow.setPayerActType(tradeOrder.getPayeeActType());
			refundFlow.setOriginOrderNo(tradeOrder.getOriginOrderNo());
			refundFlow.setPayeeUserId(tradeOrder.getPayerUserId());
			refundFlow.setPayeeUserType(tradeOrder.getPayerUserType());
			
			refundOrderType = RefundOrderType.CHARGE_TRADE;
			innerRemak = RefundOrderType.CHARGE_TRADE.getValue() + "|" +chargeOrder.getPayFlowNo() + "|" + tradeOrder.getPayFlowNo();
						
			request = new ReqRefund();
			request.setAmount((int) amount);
			request.setAttach(attach);
			request.setCallbackUrl("");
			request.setOriginOrderId(chargeOrder.getPayFlowNo());
			request.setOriginOrderNo(chargeOrder.getOriginOrderNo());	
			request.setOrderId(payFlowNo);  //支付中心退款订单号			
		}

		refundFlow.setInnerRemark(innerRemak);
		recordOrder(refundFlow);
		
		if (refundOrderType == RefundOrderType.TRADE) { //余额支付退款
			resp = balanceTradeRefund(tradeOrder, amount, feeAmount, payFlowNo, attach, businessType);
		}
		
		
		if (request != null) {
			LOG.info("GateWay Refund Request:"+JSONObject.toJSONString(request));
			RefundRpcService refundRpcService = dubboConsumerFactory.getDubboClient("gatewayRefundRpcService");		
			resp = refundRpcService.refund(request);
			LOG.info("GateWay Refund Response:"+JSONObject.toJSONString(resp));
		}

		return handRefundResult(resp, false);
	}

	
	@Override
	public PayCoreResult handRefundResult(RespRefund result, boolean callOrder) {
		if (result == null) {
			LOG.error("调用支付网关退款无响应");
			throw new BusinessException("系统繁忙，请稍后再试");
		}

		String channelBankId = result.getChannelBankId();
		String channelId = result.getChannelId();
		String orderId = result.getOrderId();
		String gatewayOrderId = result.getRefundOrderId();
		Integer status = result.getRefundStatus();
		String statusDesc = result.getRefundStatusDesc();
		String resultCode = result.getResultCode();
		String resultMsg = result.getResultMsg();

		if (!RespRefund.RC_OK.equals(resultCode)) {
			LOG.error("订单调用网关退款处理失败：" + JSONObject.toJSONString(result));
			throw new BusinessException(resultMsg);
		}

		PayCoreResult payCoreResult = null;

		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.handRefundResult");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		try {

			PayFlowDO payFlow = payFlowMysqlDAO.findByIdLock(orderId);
			if (payFlow == null) {
				LOG.error("支付中心未查询到订单：" + orderId);
				throw new BusinessException("支付中心支付结果处理异常：" + JSONObject.toJSONString(result));
			}

			String innerRemark = payFlow.getInnerRemark();

			long amount = payFlow.getAmount();
			long feeAmount = payFlow.getFeeAmount();
			String originOrderNo = payFlow.getOriginOrderNo();

			RefundOrderType refundOrderType = null;

			String chargeOrderId = null;
			String tradeOrderId = null;
			if (StringUtil.isNotBlank(innerRemark)) {
				String[] temp = innerRemark.split("\\|");
				if (temp != null && temp.length >= 2) {
					refundOrderType = RefundOrderType.valueOf(Integer.parseInt(temp[0]));
					switch (refundOrderType) {
					case CHARAGE:
						chargeOrderId = temp[1];
						break;
					case TRADE:
						tradeOrderId = temp[1];
						break;
					case CHARGE_TRADE:
						chargeOrderId = temp[1];
						tradeOrderId = temp[2];
						break;
					}
				}
			}

			String refundOrderId = payFlow.getTradeOrderNo();

			payCoreResult = new PayCoreResult();
			payCoreResult.setPayFlowNo(orderId);
			payCoreResult.setReferOrderId(refundOrderId);
			payCoreResult.setChannelId(channelId);
			payCoreResult.setChannelBankId(channelBankId);
			int oldStatus = payFlow.getPayStatus();
			LOG.info("oldStatus:" + oldStatus + " refundOrderId:"+ refundOrderId);
			if (Constance.PayFlowState.WAITING_PAY.getCode() != oldStatus && Constance.PayFlowState.PAYING.getCode() != oldStatus) {
				// 订单状态为成功、失败、异常不做处理
				LOG.info("order no handle" + " refundOrderId:" + refundOrderId);

				payCoreResult.setTradeSataus(payFlow.getPayStatus());
				payCoreResult.setTradeDesc(payFlow.getRemark());
				// payCoreResult.setChannelId(payFlow.getPayChannelId());

				return payCoreResult;
			}

			PayFlowDO updatePayFlow = null;
			PayCoreTradeInfo tradeInfo = null;

			// 只处理订单状态为待支付和支付中的订单
			Date mDate = new Date();
			updatePayFlow = new PayFlowDO();
			if (Constance.CHANNEL_ID_SZTF.equals(channelId)){
				updatePayFlow.setPayerTfActNo(Constance.ACT_SZTX_CASH);
			}
			
			updatePayFlow.setPayFlowNo(orderId);
			updatePayFlow.setGatewayOrderNo(gatewayOrderId);
			updatePayFlow.setPayChannelId(channelId);
			updatePayFlow.setModifyTime(mDate);
			updatePayFlow.setRemark(statusDesc);
			tradeInfo = null;
			if (RefundStatus.RS_SUCCEEDED == status) { // 支付成功
				updatePayFlow.setPayTime(mDate);
				updatePayFlow.setPayStatus(Constance.PayFlowState.SUCCESS.getCode()); // 1未支付 2 支付中 3 成功 4 失败 5 异常
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.SUCCESS.getDesc());
				// updatePayFlow.setPayType(payType);
				payCoreResult.setTradeSataus(Constance.PayFlowState.SUCCESS.getCode());

				switch (refundOrderType) {
				case CHARAGE:
					PayFlowDO chargeOrder = payFlowMysqlDAO.findById(chargeOrderId); // 充值单
					String payeeActNo = chargeOrder.getPayeeActNo();

					actService.unfreezeMoney(payeeActNo, amount, originOrderNo, orderId, new Date(), TradeOrderType.REFUND_ORDER, "退款成功解冻金额", "admin", chargeOrder.getBusinessType());
					actService.transferAct(payeeActNo, Constance.ACT_SZTX, amount - feeAmount, originOrderNo, orderId, TradeOrderType.REFUND_ORDER, payFlow.getRemark(), chargeOrder.getBusinessType());
					if (feeAmount > 0) {
						actService.transferAct(payeeActNo, Constance.ACT_PROFIT, feeAmount, originOrderNo, orderId, TradeOrderType.TRADE_FEE, "退款手续费", chargeOrder.getBusinessType());
					}
					break;
				case CHARGE_TRADE:
					PayFlowDO tradeOrder = payFlowMysqlDAO.findById(tradeOrderId); // 交易单
					payeeActNo = tradeOrder.getPayeeActNo();

					actService.transferAct(payeeActNo, Constance.ACT_SZTX, amount - feeAmount, originOrderNo, orderId, TradeOrderType.REFUND_ORDER, payFlow.getRemark(), tradeOrder.getBusinessType());
					if (feeAmount > 0) {
						actService.transferAct(payeeActNo, Constance.ACT_PROFIT, feeAmount, originOrderNo, orderId, TradeOrderType.TRADE_FEE, "退款手续费", tradeOrder.getBusinessType());
					}

					break;
				default:
					break;
				}

				// TODO 支付订单状态变更通知订单系统
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setAmount(payFlow.getAmount());
				tradeInfo.setPayFlowState(PayFlowState.SUCCESS);

			} else if (RefundStatus.RS_FAILED == status) {// 支付失败
				updatePayFlow.setPayStatus(Constance.PayFlowState.FAIL.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.FAIL.getDesc());
				payCoreResult.setTradeSataus(Constance.PayFlowState.FAIL.getCode());
				// TODO 支付订单状态变更通知订单系统
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.FAIL);
				// TODO 返回状态为RS_INITIALIZING(0)的处理为支付中
			} else if (RefundStatus.RS_PROCESSING == status || RefundStatus.RS_ACCEPTED == status || RefundStatus.RS_INITIALIZING == status) {// 支付中

				// 1.原订单状态为待支付则更改支付状态
				updatePayFlow.setPayStatus(Constance.PayFlowState.PAYING.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.PAYING.getDesc());
				// 2.原订单状态为支付中则不予处理
				if (oldStatus == Constance.PayFlowState.PAYING.getCode()) {
					updatePayFlow = null;
				}

				payCoreResult.setTradeSataus(Constance.PayFlowState.PAYING.getCode());
				// payCoreResult.setChannelId(channelId);
			} else {
				updatePayFlow.setPayStatus(Constance.PayFlowState.EXCEPTION.getCode());
				updatePayFlow.setPayStatusDesc(Constance.PayFlowState.EXCEPTION.getDesc());
				payCoreResult.setTradeSataus(Constance.PayFlowState.EXCEPTION.getCode());
				// TODO 订单状态异常需要预警进行人工干预
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.EXCEPTION);
			}

			if (updatePayFlow != null) {
				payFlowMysqlDAO.update(updatePayFlow);
			}
			// }
			if (callOrder && tradeInfo != null) {
				tradeInfo.setPayFlowType(PayFlowType.valueOf(payFlow.getPayType()));
				tradeInfo.setPayFlowDesc(statusDesc);
				tradeInfo.setChannelId(channelId);
				tradeInfo.setChannelBankId(channelBankId);

				callBackOrder(tradeInfo, payFlow, payFlow.getCallBackServiceName());
			}
			
		} catch (Exception ex)  {
			txManager.rollback(transactionStatus);
			LOG.error("处理退款结果出错", ex);
			throw new BusinessException(ex);
		}finally{
			if (!transactionStatus.isCompleted()) {
				txManager.commit(transactionStatus);
			}			
		}

		
		return payCoreResult;
	}

	private RespRefund balanceTradeRefund(PayFlowDO tradeOrder, long amount, long feeAmount, String payFlowNo, String attach, String businessType){		
		RespRefund resp = new RespRefund();
		resp.setChannelBankId(Constance.BERBON_PAY_BANKID);
		resp.setChannelId(Constance.CHANNEL_ID_SZTX);
		resp.setOrderId(payFlowNo);
		resp.setRefundOrderId(null); //余额退款没有网关订单号
		resp.setResultCode(RespRefund.RC_OK);
		resp.setResultMsg(RespRefund.RM_OK);
		
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.balanceTradeRefund");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		try {
			
			if (feeAmount > 0) {
				actService.transferAct(tradeOrder.getPayeeActNo(), tradeOrder.getPayerActNo(), amount - feeAmount, tradeOrder.getOriginOrderNo(), payFlowNo, TradeOrderType.REFUND_ORDER, attach, businessType);
				actService.transferAct(tradeOrder.getPayeeActNo(), Constance.ACT_PROFIT, feeAmount, tradeOrder.getOriginOrderNo(), payFlowNo, TradeOrderType.TRADE_FEE, "退款手续费", businessType);				
			}else {
				actService.transferAct(tradeOrder.getPayeeActNo(), tradeOrder.getPayerActNo(), amount, tradeOrder.getOriginOrderNo(), payFlowNo, TradeOrderType.REFUND_ORDER, attach, businessType);
			}
			
			resp.setRefundStatus(RefundStatus.RS_SUCCEEDED);
			resp.setRefundStatusDesc(RefundStatus.RSD_SUCCEEDED);
			
			
		} catch (Exception e) {
			txManager.rollback(transactionStatus);
			LOG.error("处理余额退款结果出错", e);
			resp.setRefundStatus(RefundStatus.RS_FAILED);
			resp.setRefundStatusDesc(e.getMessage());
		}finally{
			if (!transactionStatus.isCompleted()) {
				txManager.commit(transactionStatus);
			}		
		}
		
		return resp;	
	}

	@Override
	public void balancePay(PayCoreBalancePay balancePay) {	
		
		ValidateUtil.notNull(balancePay, "请求参数不能为空");				
		long amount = balancePay.getAmount();
		String payerUserId = balancePay.getPayerUserId();
		Integer payerUserType = balancePay.getPayerUserType();
		String payerActNo = balancePay.getPayerActNo();
		UserActType payerActType = balancePay.getPayerActType();
		String payeeUserId = balancePay.getPayeeUserId();
		Integer payeeUserType = balancePay.getPayeeUserType();
		String payeeActNo = balancePay.getPayeeActNo();
		UserActType payeeActType = balancePay.getPayeeActType();
		String attach = balancePay.getAttach();
		String orderId = balancePay.getOrderId();
		String originOrderId = balancePay.getOriginOrderId();
		TradeOrderType tradeOrderType = balancePay.getTradeOrderType();
		String businessType = balancePay.getBusinessType();
				
		ValidateUtil.gt(amount, 0l, "交易金额必须大于0");
		ValidateUtil.notEmpty(payerUserId, "payerUserId不能为空");	
		ValidateUtil.notNull(payerUserType, "payerUserType不能为空");	
		ValidateUtil.notEmpty(payerActNo, "payerActNo不能为空");	
		ValidateUtil.notNull(payerActType, "payerActType不能为空");	
		ValidateUtil.notEmpty(payeeUserId, "payeeUserId不能为空");	
		ValidateUtil.notNull(payeeUserType, "payeeUserType不能为空");	
		ValidateUtil.notEmpty(payeeActNo, "payeeActNo不能为空");	
		ValidateUtil.notNull(payeeActType, "payeeActType不能为空");
		ValidateUtil.notEmpty(orderId, "orderId不能为空");
		ValidateUtil.notEmpty(originOrderId, "originOrderId不能为空");
		ValidateUtil.notNull(tradeOrderType, "tradeOrderType不能为空");
		
		if (payerActType != UserActType.CASH && payerActType != UserActType.JF) { //付款方必须为现金账户
			LOG.warn("付款用户"+payerUserId+"账户"+payerActNo+"不是现金账户，不允许交易");
			throw new BusinessException("付款账户传入错误");
		}
		
		if (payeeActType != UserActType.TRADE) { //收款方必须为收款账户
			LOG.warn("收款用户"+payeeUserId+"账户"+payeeActNo+"不是收款账户，不允许交易");
			throw new BusinessException("收款账户传入错误");
		}
		
		String payFlowNo = billnoService.nexPayFlowNo();	
		PayFlowDO payFlow = new PayFlowDO();
		
		payFlow.setPayFlowNo(payFlowNo);		
		payFlow.setPayerUserId(payerUserId);
		payFlow.setPayerUserType(payerUserType);
		payFlow.setPayerActNo(payerActNo);	
		payFlow.setPayerActType(payerActType.getCode());
		
		payFlow.setPayeeUserId(payeeUserId);
		payFlow.setPayeeUserType(payeeUserType);
		payFlow.setPayeeActNo(payeeActNo);
		payFlow.setPayeeActType(payeeActType.getCode());
		
		payFlow.setTradeOrderNo(orderId);
		payFlow.setTradeOrderType(tradeOrderType.getCode());
		payFlow.setAmount(amount);
		payFlow.setPayType(PayFlowType.BALANCE_TRADE.getCode());
		payFlow.setInnerRemark(PayFlowType.BALANCE_TRADE.getDesc());
		payFlow.setRemark(attach);
		payFlow.setPayStatus(PayFlowState.WAITING_PAY.getCode());
		payFlow.setOriginOrderNo(originOrderId);
		payFlow.setPayStatusDesc(PayFlowState.WAITING_PAY.getDesc());	
		payFlow.setBusinessType(businessType);
		payFlow.setFeeAmount(0l);
		
		
		recordOrder(payFlow);
		
		//更新payFlow状态为成功
		PayFlowDO updatePayFlow = new PayFlowDO();
		updatePayFlow.setPayFlowNo(payFlowNo);
		updatePayFlow.setPayChannelId(Constance.CHANNEL_ID_SZTX);
		
		PayFlowState payState = PayFlowState.SUCCESS;
		String remark = "";
		try {
			balanceTrade(payerActNo, payeeActNo, amount, originOrderId, payFlowNo, tradeOrderType, attach, businessType);
		} catch (Exception e) {
			payState = PayFlowState.FAIL;
			remark = e.getMessage();
			
			if (remark != null && remark.length() > 255) {
				remark = payState.getDesc();
			}			
		}
		
		updatePayFlow.setPayStatus(payState.getCode());
		updatePayFlow.setPayStatusDesc(payState.getDesc());	
		updatePayFlow.setRemark(remark);
		if (payState == PayFlowState.SUCCESS) {
			updatePayFlow.setPayTime(new Date());
		}		
		payFlowMysqlDAO.update(updatePayFlow);
		
		
		if (payState == PayFlowState.FAIL) {
			throw new BusinessException(remark);
		}
		
		
	}

	

	private void balanceTrade(String payerActNo, String payeeActNo, long amount, String originOrderId, String payFlowId, TradeOrderType tradeOrderType, String attach, String businessType){
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.balanceTrade");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		try {
			
//			actService.subMoney(payerActNo, amount, originOrderId, payFlowId, null, tradeOrderType, attach, businessType);
//			actService.plusMoney(payeeActNo, amount, originOrderId, payFlowId, null, tradeOrderType, attach, businessType);	
//			
			actService.transferAct(payerActNo, payeeActNo, amount, originOrderId, payFlowId, tradeOrderType, attach, businessType);
		
			txManager.commit(transactionStatus);
		}catch (Exception e) {
			txManager.rollback(transactionStatus);
			LOG.error("余额交易失败", e);
			throw new BusinessException(e.getMessage(), e);
		}
		
			
	}
	

	@Override
	public void balanceTransfer(PayCoreTransferReq req) {
		ValidateUtil.notNull(req, "请求参数不能为空");				
		long amount = req.getAmount();
		String payerUserId = req.getPayerUserId();
		Integer payerUserType = req.getPayerUserType();
		String payerActNo = req.getPayerActNo();
		UserActType payerActType = req.getPayerActType();
		String payeeUserId = req.getPayeeUserId();
		Integer payeeUserType = req.getPayeeUserType();
		String payeeActNo = req.getPayeeActNo();
		UserActType payeeActType = req.getPayeeActType();
		String attach = req.getAttach();
		String orderId = req.getOrderId();
		String originOrderId = req.getOriginOrderId();
		TradeOrderType tradeOrderType = req.getTradeOrderType();
		long feeAmount = req.getFeeAmount();		
		String businessType = req.getBusinessType();
		
		ValidateUtil.gt(amount, 0l, "交易金额必须大于0");
		ValidateUtil.notEmpty(payerUserId, "payerUserId不能为空");	
		ValidateUtil.notNull(payerUserType, "payerUserType不能为空");	
		ValidateUtil.notEmpty(payerActNo, "payerActNo不能为空");	
		ValidateUtil.notNull(payerActType, "payerActType不能为空");	
		ValidateUtil.notEmpty(payeeUserId, "payeeUserId不能为空");	
		ValidateUtil.notNull(payeeUserType, "payeeUserType不能为空");	
		ValidateUtil.notEmpty(payeeActNo, "payeeActNo不能为空");	
		ValidateUtil.notNull(payeeActType, "payeeActType不能为空");
		ValidateUtil.notEmpty(orderId, "orderId不能为空");
		ValidateUtil.notEmpty(originOrderId, "originOrderId不能为空");
		ValidateUtil.notNull(tradeOrderType, "tradeOrderType不能为空");
		
		String payFlowNo = billnoService.nexPayFlowNo();	
		PayFlowDO payFlow = new PayFlowDO();
		
		payFlow.setPayFlowNo(payFlowNo);		
		payFlow.setPayerUserId(payerUserId);
		payFlow.setPayerUserType(payerUserType);
		payFlow.setPayerActNo(payerActNo);	
		payFlow.setPayerActType(payerActType.getCode());
		
		payFlow.setPayeeUserId(payeeUserId);
		payFlow.setPayeeUserType(payeeUserType);
		payFlow.setPayeeActNo(payeeActNo);
		payFlow.setPayeeActType(payeeActType.getCode());
		
		payFlow.setTradeOrderNo(orderId);
		payFlow.setTradeOrderType(tradeOrderType.getCode());
		payFlow.setAmount(amount);
		payFlow.setFeeAmount(feeAmount);
		payFlow.setPayType(PayFlowType.TRANSFER.getCode());
		payFlow.setInnerRemark(PayFlowType.TRANSFER.getDesc());
		payFlow.setRemark(attach);
		payFlow.setPayStatus(PayFlowState.WAITING_PAY.getCode());
		payFlow.setOriginOrderNo(originOrderId);
		payFlow.setPayStatusDesc(PayFlowState.WAITING_PAY.getDesc());	
		payFlow.setBusinessType(businessType);
		payFlow.setPayChannelId(Constance.CHANNEL_ID_SZTX);
		
		recordOrder(payFlow);
			
		
		try {
			actService.transferAct(payerActNo, payeeActNo, amount, originOrderId, payFlowNo, tradeOrderType, attach, businessType);
		} catch (BusinessException e) {
			LOG.info("", e);
			PayFlowDO updatePayFlowDO = new PayFlowDO();
			updatePayFlowDO.setPayFlowNo(payFlow.getPayFlowNo());
			updatePayFlowDO.setPayStatus(PayFlowState.FAIL.getCode());
			updatePayFlowDO.setPayStatusDesc(e.getMessage());
			payFlowMysqlDAO.update(updatePayFlowDO);
			throw e;
		} catch (Exception e) {
			LOG.info("", e);
			PayFlowDO updatePayFlowDO = new PayFlowDO();
			updatePayFlowDO.setPayFlowNo(payFlow.getPayFlowNo());
			updatePayFlowDO.setPayStatus(PayFlowState.EXCEPTION.getCode());
			updatePayFlowDO.setPayStatusDesc("未知错误!");
			payFlowMysqlDAO.update(updatePayFlowDO);
			throw e;
		}
		
		PayFlowDO updatePayFlowDO = new PayFlowDO();
		updatePayFlowDO.setPayFlowNo(payFlow.getPayFlowNo());
		updatePayFlowDO.setPayStatus(PayFlowState.SUCCESS.getCode());
		updatePayFlowDO.setPayStatusDesc(PayFlowState.SUCCESS.getDesc());
		payFlowMysqlDAO.update(updatePayFlowDO);
	}

	
	@Override
	public void batchBalanceTransfer(BatchPayCoreTransferReq req) {
		
		String orderId = req.getBatchOrderId();
		long totalAmount = req.getTotalAmount();

		List<BatchTransferDetail> detailList = req.getPayeeInfoList();
		
		ValidateUtil.isNotBlank(orderId, "orderId不能为空");			
		ValidateUtil.notEmpty(detailList, "payeeList不能为空");
		
//		ValidateUtil.isNotBlank(payerUserId, "payerUserId不能为空");
//		UserInfoDO payerUserInfo = userInfoService.findUserInfo(payerUserId);
//		ValidateUtil.notNull(payerUserInfo, "用户"+payerUserId+"不存在");
//		ValidateUtil.gt(totalAmount, 0l, "结算总金额必须大于0");
//		int payerUserType = payerUserInfo.getUserType();
//		
//		UserActDO payerAct = actService.findUserAct(payerUserId, UserActType.TRADE);
//		ValidateUtil.notNull(payerUserInfo, "用户"+payerUserId+"交易账户不存在");		
//		String payerActNo = payerAct.getActNo();
		
		List<BatchActTransferReq> list = new ArrayList<BatchActTransferReq>();	
		List<PayFlowDO> payFlowList = new ArrayList<PayFlowDO>();
		long settleTotal = 0; //结算总金额
		
		for (BatchTransferDetail transferDetail : detailList) {
			String payerActNo = transferDetail.getPayerActNo();
			Integer payerUserType = transferDetail.getPayerUserType();
			
			String originOrderId = transferDetail.getOriginOrderId();
			String payerUserId = transferDetail.getPayerUserId();
			
			String subSettleOrder = transferDetail.getSubOrderNo();
			String payeeUserId = transferDetail.getPayeeUserId();
			UserActType payeeActType = transferDetail.getPayeeActType();			
			TradeOrderType tradeType = transferDetail.getTradeOrderType();
			long amount = transferDetail.getAmount();
			String attach = transferDetail.getAttach();	
			String payeeActNo = transferDetail.getPayeeActNo();
			Integer payeeUserType = transferDetail.getPayeeUserType();
			String businessType = transferDetail.getBusinessType();
				
			ValidateUtil.notEmpty(subSettleOrder, "subSettleOrder不能为空");
			ValidateUtil.notEmpty(payeeUserId, "payeeUserId不能为空");
			ValidateUtil.notNull(payeeActType, "payeeUserActType不能为空");			
			ValidateUtil.gt(amount, 0l, "结算金额必须大于0");
				
			settleTotal += amount;
				
			String payFlowNo = billnoService.nexPayFlowNo();
			BatchActTransferReq transferReq = new BatchActTransferReq();
			transferReq.setAmount(amount);
			transferReq.setSrcActNo(payerActNo);
			transferReq.setOriginOrderNo(originOrderId);
			transferReq.setPayFlowId(payFlowNo);
			transferReq.setPayOrderId(subSettleOrder);
			transferReq.setDesActNo(payeeActNo);
			transferReq.setTradeType(tradeType);
			transferReq.setTradeMsg(attach);
			transferReq.setBusinessType(businessType);
			
			PayFlowDO payFlow = new PayFlowDO();		
			payFlow.setBatchOrderId(orderId);
			payFlow.setPayFlowNo(payFlowNo);
				
			payFlow.setPayerUserId(payerUserId);
			
			payFlow.setPayerUserType(payerUserType);
			payFlow.setPayerActNo(payerActNo);	
			payFlow.setPayerActType(UserActType.TRADE.getCode());
				
			payFlow.setPayeeUserId(payeeUserId);
			payFlow.setPayeeUserType(payeeUserType);
			payFlow.setPayeeActNo(payeeActNo);
			payFlow.setPayeeActType(payeeActType.getCode());
				
			payFlow.setTradeOrderNo(subSettleOrder);
			payFlow.setTradeOrderType(tradeType.getCode());
			payFlow.setAmount(amount);
			payFlow.setPayType(PayFlowType.BALANCE_BATCH_TRASFER.getCode());
			payFlow.setRemark(attach);
			payFlow.setPayStatus(PayFlowState.WAITING_PAY.getCode());
			payFlow.setOriginOrderNo(originOrderId);
			payFlow.setBusinessType(businessType);
			payFlow.setFeeAmount(0l);
			
			payFlowList.add(payFlow);				
			
			
			list.add(transferReq);
		}		
		
		if (totalAmount != settleTotal) {
			throw new BusinessException("结算明细金金额与结算总金额不相等");
		}
		
		payFlowMysqlDAO.batchSave(payFlowList);
		try {
			actService.bacthTransferActs(list);	
		} catch (BusinessException e) {
			LOG.info("", e);
			for (PayFlowDO payFlowDO : payFlowList) {
				PayFlowDO updatePayFlowDO = new PayFlowDO();
				updatePayFlowDO.setPayFlowNo(payFlowDO.getPayFlowNo());
				updatePayFlowDO.setPayStatus(PayFlowState.FAIL.getCode());
				updatePayFlowDO.setPayStatusDesc(e.getMessage());
				payFlowMysqlDAO.update(updatePayFlowDO);
			}
			throw e;
		} catch (Exception e) {
			LOG.info("", e);
			for (PayFlowDO payFlowDO : payFlowList) {
				PayFlowDO updatePayFlowDO = new PayFlowDO();
				updatePayFlowDO.setPayFlowNo(payFlowDO.getPayFlowNo());
				updatePayFlowDO.setPayStatus(PayFlowState.EXCEPTION.getCode());
				updatePayFlowDO.setPayStatusDesc("未知错误!");
				payFlowMysqlDAO.update(updatePayFlowDO);
			}
			throw e;
		}
		for (PayFlowDO payFlowDO : payFlowList) {
			PayFlowDO updatePayFlowDO = new PayFlowDO();
			updatePayFlowDO.setPayFlowNo(payFlowDO.getPayFlowNo());
			updatePayFlowDO.setPayStatus(PayFlowState.SUCCESS.getCode());
			updatePayFlowDO.setPayStatusDesc(PayFlowState.SUCCESS.getDesc());
			payFlowMysqlDAO.update(updatePayFlowDO);
		}
	}
	
	
	@Override
	public PayCoreResult transfer(PayCoreTransfer payCoreTransfer, String serviceName, String originOrderId) {
		PayFlowDO payFlow = new PayFlowDO();

		payFlow.setPayerUserId(payCoreTransfer.getPayerUserId());
		
		Integer payerUserType = payCoreTransfer.getPayerUserType();		
		payFlow.setPayerUserType(payerUserType);
		
		payFlow.setPayerActNo(payCoreTransfer.getPayerAccountId());	
		Integer payerActType = payCoreTransfer.getPayerActType() == null ? null:payCoreTransfer.getPayerActType().getCode();
		payFlow.setPayerActType(payerActType);
		
		payFlow.setPayerTfActNo(payCoreTransfer.getPayerTfActNo());
		
		payFlow.setPayeeUserId(payCoreTransfer.getPayeeUserId());
		Integer payeeUserType = payCoreTransfer.getPayeeUserType();	
		payFlow.setPayeeUserType(payeeUserType);
		payFlow.setPayeeActNo(payCoreTransfer.getPayeeAccountId());
		Integer payeeActType = payCoreTransfer.getPayeeActType() == null ? null:payCoreTransfer.getPayeeActType().getCode();
		payFlow.setPayeeActType(payeeActType);
		
		payFlow.setPayeeTfActNo(payCoreTransfer.getPayeeTfActNo());
		
		payFlow.setTradeOrderNo(payCoreTransfer.getReferOrderId());
		payFlow.setTradeOrderType(payCoreTransfer.getTradeOrderType().getCode());
		payFlow.setAmount(payCoreTransfer.getAmount());
		payFlow.setPayType(Constance.PayFlowType.TRANSFER.getCode());
		payFlow.setRemark(payCoreTransfer.getAttach());
		payFlow.setOriginOrderNo(originOrderId);
		
		payFlow.setCallBackServiceName(serviceName);
		payFlow.setBusinessType(payCoreTransfer.getBusinessType());
		String payFlowNo = recordOrder(payFlow);

		TransferRpcService transferRpcService = dubboConsumerFactory.getDubboClient("transferRpcService");		
		ReqTransfer request = new ReqTransfer();
		
		long amount = payCoreTransfer.getAmount();
		String attach = payCoreTransfer.getAttach();		
		String dstAccountId = payCoreTransfer.getPayeeTfActNo();
		String dstUserId = payCoreTransfer.getPayeeUserId();
		String srcAccountId = payCoreTransfer.getPayerTfActNo();
		String srcUserId = payCoreTransfer.getPayerUserId();
		String transferBankId = Constance.TRANSFER_BANK_ID;
		int transferType = payCoreTransfer.getInnerTransferType().getCode();
		String callbackUrl = "";
		
		request.setAmount((int) amount);		
		request.setAttach(attach);		
		request.setCallbackUrl(callbackUrl);		
		request.setDstAccountId(dstAccountId);
		request.setDstUserId(dstUserId);
		request.setOrderId(payFlowNo);		
		request.setSrcAccountId(srcAccountId);		
		request.setSrcUserId(srcUserId);
		request.setTransferBankId(transferBankId);
		request.setTransferType(transferType);
		request.setOriginOrderNo(originOrderId);
		
		
		LOG.info("GateWay Transfer Request:" + JSONObject.toJSONString(request));
		
		RespTransfer respTransfer = transferRpcService.transfer(request );
		
		return handTransferResult(respTransfer, false);
	}
	
	
	@Override
	public PayCoreResult handTransferResult(RespTransfer result, boolean callOrder) {
		
		if (result == null) {
			LOG.error("调用支付网关转账无响应");
			throw new BusinessException("系统繁忙，请稍后再试");
		}
		LOG.info("GateWay Transfer Response:" + JSONObject.toJSONString(result));
		
//		String bankId = result.getChannelBankId();// 转账只是通付的余额转账
		String channelId = result.getChannelId();
		String payFlowNo = result.getOrderId();
		String resultCode = result.getResultCode();
		String resultMsg = result.getResultMsg();
		String transferOrderId = result.getTransferOrderId();
		int status = result.getTransferStatus();
		String statusDesc = result.getTransferStatusDesc();
		
		if (!RespTransfer.RC_OK.equals(resultCode)) {
			LOG.error("订单调用网关转账处理失败："+JSONObject.toJSONString(result));
			throw new BusinessException(resultMsg);
		}		
		
		//根据支付订单号查询订单
		//TODO 此处查询订单需要从主库查询
		PayFlowDO payFlow = null;
		PayCoreResult payCoreResult = null;
		PayFlowDO updatePayFlow = null;
		
		PayCoreTradeInfo tradeInfo = null;
		
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.core.service.impl.PayCoreServiceImpl.handTransferResult");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		try {
			payFlow = payFlowMysqlDAO.findById(payFlowNo);
			if (payFlow == null) {
				LOG.error("支付中心未查询到订单：" + payFlowNo);
				throw new BusinessException("支付中心支付结果处理异常："
						+ JSONObject.toJSONString(result));
			}
			payCoreResult = new PayCoreResult();
			payCoreResult.setPayFlowNo(payFlowNo);
			payCoreResult.setReferOrderId(payFlow.getTradeOrderNo());
			int oldStatus = payFlow.getPayStatus();
			if (Constance.PayFlowState.WAITING_PAY.getCode() != oldStatus
					&& Constance.PayFlowState.PAYING.getCode() != oldStatus) {
				//订单状态为成功、失败、异常不做处理
				return null;
			}
			//只处理订单状态为待支付和支付中的订单
			Date mDate = new Date();
			updatePayFlow = new PayFlowDO();
			updatePayFlow.setPayFlowNo(payFlowNo);
			updatePayFlow.setGatewayOrderNo(transferOrderId);
			updatePayFlow.setPayChannelId(channelId);
			updatePayFlow.setModifyTime(mDate);
			updatePayFlow.setRemark(statusDesc);
			tradeInfo = null;
			if (TradeStatus.TS_SUCCEEDED == status) { //支付成功
				updatePayFlow.setPayTime(mDate);
				updatePayFlow.setPayStatus(Constance.PayFlowState.SUCCESS
						.getCode()); //1未支付   2 支付中  3 成功 4 失败 5 异常 	 
				//			updatePayFlow.setPayType(payType);
				payCoreResult.setTradeSataus(Constance.PayFlowState.SUCCESS
						.getCode());

				//TODO 支付订单状态变更通知订单系统
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setAmount(payFlow.getAmount());
				tradeInfo.setPayFlowState(PayFlowState.SUCCESS);

			} else if (TradeStatus.TS_FAILED == status) {//支付失败
				updatePayFlow.setPayStatus(Constance.PayFlowState.FAIL.getCode());
				payCoreResult.setTradeSataus(Constance.PayFlowState.FAIL.getCode());

				//TODO 支付订单状态变更通知订单系统	
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.FAIL);
			} else if (TradeStatus.TS_PAYING == status) {//支付中

				//1.原订单状态为待支付则更改支付状态				
				updatePayFlow.setPayStatus(Constance.PayFlowState.PAYING
						.getCode());

				//2.原订单状态为支付中则不予处理
				if (oldStatus == Constance.PayFlowState.PAYING.getCode()) {
					updatePayFlow = null;
				}

				payCoreResult.setTradeSataus(Constance.PayFlowState.PAYING
						.getCode());
				payCoreResult.setChannelId(channelId);
			} else {
				updatePayFlow.setPayStatus(Constance.PayFlowState.EXCEPTION
						.getCode());
				//TODO  订单状态异常需要预警进行人工干预
				tradeInfo = new PayCoreTradeInfo();
				tradeInfo.setPayFlowState(PayFlowState.EXCEPTION);
			}
			
			if (updatePayFlow != null) {		
				payFlowMysqlDAO.update(updatePayFlow);
			}

			
		}catch (Exception e) {
			txManager.rollback(transactionStatus);			
			LOG.error("处理转账结果失败", e);			
			throw new BusinessException(e);
		}finally{			
			if (!transactionStatus.isCompleted()) {
				txManager.commit(transactionStatus);
			}		
		}
		
		
		if (callOrder  && tradeInfo != null) {				
			callBackOrder(tradeInfo, payFlow,  payFlow.getCallBackServiceName());
		}

		return payCoreResult;
	}

	class CallBackThread implements Runnable{
		
		private PayCoreTradeInfo tradeInfo;
		private PayFlowDO payFlow;
		private String serviceName;
		private String msgno;

		public CallBackThread(PayCoreTradeInfo tradeInfo, PayFlowDO payFlow, String serviceName, String msgno) {
			super();
			this.tradeInfo = tradeInfo;
			this.payFlow = payFlow;
			this.serviceName = serviceName;
			this.msgno = msgno;
		}

		@Override
		public void run() {
			try {
				
				LogMsgNoConverter.setMsgno(msgno);
				
				LOG.info("------------------------");
				
				if (tradeInfo == null) {
					LOG.info("tradeInfo为空不回调通知"+serviceName);
					return;
				}
				
				if (StringUtil.isBlank(serviceName)) {
					LOG.info("serviceName为空，支付中心不回调");
					return;
				}
				
				if (payFlow != null) {
					tradeInfo.setPayCoreOrderId(payFlow.getPayFlowNo());
					tradeInfo.setPayerUserId(payFlow.getPayerUserId());
					tradeInfo.setPayerUserType(payFlow.getPayerUserType());
					tradeInfo.setPayeeUserId(payFlow.getPayeeUserId());
					tradeInfo.setPayeeUserType(payFlow.getPayeeUserType());
					tradeInfo.setPayFlowType(PayFlowType.valueOf(payFlow.getPayType()));
					tradeInfo.setReferOrderId(payFlow.getTradeOrderNo());
					tradeInfo.setTradeOrderType(TradeOrderType.valueOf(payFlow.getTradeOrderType()));
				}
				
				try {
					PayCoreCallBack payCoreCallBack = SpringContextHolder.applicationContext.getBean(serviceName, PayCoreCallBack.class);
					if (payCoreCallBack == null) {
						LOG.error("未找到"+serviceName+"服务");
						return;
					}
					
					
					List<PayCoreTransferResult> batchTransfer = tradeInfo.getBatchTransferResult();
					if (batchTransfer != null && !batchTransfer.isEmpty()) {//批量支付暂不进行回调并发控制
						
						LOG.info("PayCoreCallBack:"+JSONObject.toJSONString(tradeInfo));
						
						payCoreCallBack.callPayResult(tradeInfo);
						return;
					}
					
					String payFlowNo = tradeInfo.getPayCoreOrderId();
					String tradeStaus = tradeInfo.getPayFlowState().getCode()+"";
					
					boolean flag = lockRedisDAO.lockOrder(payFlowNo, tradeStaus);
					if (flag) {
						payCoreCallBack.callPayResult(tradeInfo);
					}else {
						String oldOrderStatus = lockRedisDAO.getLockOrderStatus(payFlowNo);
						
						if (!tradeStaus.equals(oldOrderStatus)) {
							LOG.info("PayCoreCallBack:"+JSONObject.toJSONString(tradeInfo));
							payCoreCallBack.callPayResult(tradeInfo);
						}
					}				
				} catch (BeansException e) {
					LOG.error("回调"+serviceName+"异常", e);
				}
			} catch (Exception e) {
				LOG.error("", e);
			}finally{
				LogMsgNoConverter.clear(); //重新生成msgno
			}
			
		}
		
		
		
	}
	
	
	
}
